using System;
using System.Collections.Generic;
using System.Text;

namespace MinhUtils.Threading
{
    class Exchanger<T>
    {
        //gate 1: open
        private Semaphore _m1 = new Semaphore(1);

        //gate 2: close
        private Semaphore _m2 = new Semaphore(0);

        //I'll hold your data for you
        private T _dataHolder = default(T);
        
        //the first one is the first one :)
        private bool _isFirst = true;

        public void Exchange(ref T value)
        {
            //close gate 1 or wait for gate 1 to be opened
            _m1.Acquire();

            lock (this)
            {
                if (_isFirst) //I'm the first
                {
                    //the next one is the second
                    _isFirst = false;

                    //keep my data
                    _dataHolder = value;

                    //open gate 1
                    _m1.Release();
                }
                else //I'm the second
                {
                    //the next one is the first
                    _isFirst = true;
                    
                    //exchange data
                    T temp = value;
                    value = _dataHolder;
                    _dataHolder = temp;

                    //open gate 2
                    _m2.Release();

                    //I'm done
                    return;
                }
            }

            //wait for gate 2 to be opened
            _m2.Acquire();

            lock (this)
            {
                //exchange data
                value = _dataHolder;
                _dataHolder = default(T);

                //open gate 1
                _m1.Release();

                return;
            }
        }
    }
}
